/*
 * lab3chq21.c
 *
 *  Created on: Mar 6th, 2011
 *      Author: Vishal Verma
 */

/*
 * PROGRAM DESCRIPTION
 *
 * Run I2C bit banged.
 *
 */

/*
 * COMPILER FLAGS
 * sdcc -c --debug -mmcs51 --std-sdcc99 --model-large
 *
 * LINKER FLAGS
 * sdcc --debug -mmcs51 --code-loc 0x0000 --code-size 0x8000 --xram-loc 0x0000 --xram-size 0x8000 --model-large --out-fmt-ihx
 *
 * USAGE SPECIFICATIONS:
 * Baud rate - 57600
 */

/*==============================================INCLUDES=========================================*/
#include <at89c51ed2.h>  //also includes 8052.h and 8051.h
#include <mcs51reg.h>
#include <stdio.h>
#include <stdlib.h>
#include "i2c.h"
#include "lcd.h"

/*==============================================DEFINES==========================================*/
#define TRUE 1
#define FALSE 0
#define ON 1
#define OFF 0
#define IPSTRLENGTH 200
#define IPSMALLLEN 6

/*==============================================GLOBALS==========================================*/

enum RETCODE{							//retcodes/parameter flags for all functions
	OK = 0,
	STDERR = 5151,						//bad idea to keep 5151 but using coz needed to return an unsigned int in one place
	EINMEM = -7
};

/*=========================================FUNCTION PROTOTYPES===================================*/

void putchar (char c);
char getchar (void);
int putstr (char *s);
int getstr (char *s);
void serialInit(int);
void clearScr(void);
void myDelay(int j);
void initAll(void);

void printMenu(void);
int getInput(char *prompt, char *retStr, int sz_retStr, int f_clear, int f_noWait);
void printLcdMap(void);
int hexalpha_to_int(int c);
unsigned int htoi(const char s[]);

/*=========================================FUNCTION DEFINITIONS===================================*/

/*
* NAME :            _sdcc_external_startup
*
* DESCRIPTION :     Will run before main(). Used to initialize registers etc. as required
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	AUXR
*
* OUTPUTS :
*       GLOBALS:	AUXR
*       RETURN:		-
*
*/

_sdcc_external_startup() {

	AUXR |= 0x0C;
	AUXR &= 0x7F;
	return 0;
}

/*
* NAME :            putchar
*
* DESCRIPTION :     print 1 character to serial port
*
* INPUTS :
*       PARAMETERS:	char c
*		GLOBALS:	SCON
*
* OUTPUTS :
*       GLOBALS :	SBUF, TI
*       RETURN :	-
*
* PROCESS :
*                   [1]	Wait for port to be ready
* 					[2]	Print char and clear TI
*/

void putchar (char c) {

	while ((SCON & 0x02) == 0);    				// wait for TX ready, spin on TI
	SBUF = c;  									// load serial port with transmit value
	TI = 0;  									// clear TI flag
}

/*
* NAME :            getchar
*
* DESCRIPTION :     get 1 character from serial port
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	SCON
*
* OUTPUTS :
*       GLOBALS :	SBUF, RI
*       RETURN :	SBUF - character received
*
* PROCESS :
*                   [1]	Wait for character to be received
* 					[2]	Clear RI
*					[3] Return character
*/

char getchar () {

    while ((SCON & 0x01) == 0);  				// wait for character to be received, spin on RI
	RI = 0;										// clear RI flag
	return SBUF;  								// return character from SBUF
}

/*
* NAME :            putstr
*
* DESCRIPTION :     Print a string to serial port
*
* INPUTS :
*       PARAMETERS:	char *s
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	Number of characters transmitted
*
* PROCESS :
*                   [1]  Transmit characters till oxoo (NULL) is encountered
*/

int putstr (char *s) {

	int i = 0;
	while (*s){									// output characters until NULL found
		putchar(*s++);
		i++;
	}
	//putchar('\n\r');
	return i+1;
}

/*
* NAME :            getstr
*
* DESCRIPTION :     Get a string from serial port
*
* INPUTS :
*       PARAMETERS:	char *s
*		GLOBALS:	-
*
* OUTPUTS :
*		PARAMETERS: char *s
*       GLOBALS :	-
*       RETURN :	i - number of characters read
*
* PROCESS :
*                   [1]  Accept characters till 0x0D encountered (CR)
*					[2]	 Store starting at given location (*s)
*
* NOTES :           Is not safe from buffer overrun. Assumes valid memory available for all characters input.
*					Can be substituted with gets() which is equally unsafe but I wrote this so am going with it :)
*/

int getstr (char *s) {

	int i = 0;
	do {
		s[i] = getchar();
		putchar(s[i]);
		i++;
	} while(s[i-1] != 0x0D);  					//0x0D is <CR>
	s[i-1] = 0x00;								//replace <CR> with NULL (0x00)
	putchar('\n\r');
	return (i-1);
}

/*
* NAME :            serialInit
*
* DESCRIPTION :     Initialize the serial port
*
* INPUTS :
*       PARAMETERS:	int br (BAUD RATE)
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	PCON, SCON, TMOD, TH1, TR1, TI
*       RETURN :	-
*
*
* NOTES :  Baud rate is supplied as 0xFF for 56700 etc
*/

void serialInit(int br) {

/*
	PCON |= 0x80;								//SMOD1 = 1
	SCON = 0x50;								//uart in mode 1 (8 bit), REN=1
	BDRCON &=0xEC;								//BRR=0; SRC=0;
	BDRCON |=0x0E;								//TBCK=1;RBCK=1; SPD=1
	BRL = br;
	BRL=0xFD;									//115200 Bds at 11.059MHz
	EA = 1;										//Enable serial interrupt
	BDRCON |= 0x10;								//Baud rate generator run
*/


	PCON |= 0x80;								//configure uart, fast baud
	SCON = 0x50;                   			 	//SCON: mode 1, 8-bit UART, enable rcvr
	TMOD |= 0x20;                   			//TMOD: timer 1, mode 2, 8-bit reload for serial
	TMOD |= 0x01;                   			//TMOD: timer 1, mode 2, 8-bit reload for debounce
	TH1 = br;                   				//TH1:  reload value for baudrate
	TR1   = 1;                      			//TR1:  timer 1 run
	TI    = 1;                      			//TI:   set TI to send first char of UART
}

/*
* NAME :            initAll
*
* DESCRIPTION :     Reset global variables to initial values
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	-
*/

void initAll() {

	int i = 0;

	EA = 1;
}

/*
* NAME :            clearScr
*
* DESCRIPTION :     Clears and resets the VT100 terminal
*
* INPUTS :
*       PARAMETERS:	-
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	-
*
*
* NOTES :           Will clear the VT100 terminal by sending control sequences to reset and clear entire screen
*					Reset: ESC c
*					Clear Screen: ESC [ 2 J
*/

void clearScr() {
	printf("\033c");			//reset terminal
	printf("\033[2J");			//clear screen
}

/*
* NAME :            myDelay
*
* DESCRIPTION :     Provide a delay
*
* INPUTS :
*       PARAMETERS:	int j - empirical - j=1 ~ 1 second
*		GLOBALS:	-
*
* OUTPUTS :
*       GLOBALS :	-
*       RETURN :	-
*/

void myDelay(int j) {
	int i = 0;
	int cnt = 0;

	j*=100;
	while(j) {
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		for(i=0; i<100; i++);
		j--;
	}
}

int hexalpha_to_int(int c)
{
  char hexalpha[] = "aAbBcCdDeEfF";
  int i;
  int answer = 0;

  for(i = 0; answer == 0 && hexalpha[i] != '\0'; i++)
  {
    if(hexalpha[i] == c)
    {
      answer = 10 + (i / 2);
    }
  }

  return answer;
}

unsigned int htoi(const char s[])
{
  unsigned int answer = 0;
  int i = 0;
  int valid = 1;
  int hexit;

  if(s[i] == '0')
  {
    ++i;
    if(s[i] == 'x' || s[i] == 'X')
    {
      ++i;
    }
  }

  while(valid && s[i] != '\0')
  {
    answer = answer * 16;
    if(s[i] >= '0' && s[i] <= '9')
    {
      answer = answer + (s[i] - '0');
    }
    else
    {
      hexit = hexalpha_to_int(s[i]);
      if(hexit == 0)
      {
        valid = 0;
      }
      else
      {
        answer = answer + hexit;
      }
    }

    ++i;
  }

  if(!valid)
  {
    answer = STDERR;
  }

  return answer;
}


void printMenu() {
	clearScr();
	putstr("************************************WELCOME***********************************\n\r");
	putstr("*                                                                            *\n\r");
	putstr("*            This program will test all features of the LCD driver           *\n\r");
	putstr("*                                                                            *\n\r");
	putstr("******************************************************************************\n\n\n\r");

	putstr("1-> Clear LCD \n\r");
	putstr("2-> Goto Address\n\r");
	putstr("3-> Goto (x,y)\n\r");
	putstr("4-> Write Character \n\r");
	putstr("5-> Write String \n\r");
	putstr("6-> Write (Truncated) to specific line \n\r");
	putstr("7-> Clear specific line \n\r");
	putstr("8-> Go Home \n\r\n\r");

	putstr("******************************************************************************\n\r\n\r");
	putstr("Command > ");
}

void printLcdMap() {
	putstr("Valid Cursor addresses: \n\r\n\r");
	putstr("|--------------------------------------|\n\r");
	putstr("|0x00            Line 0            0x0F|\n\r");
	putstr("|--------------------------------------|\n\r");
	putstr("|0x40            Line 1            0x4F|\n\r");
	putstr("|--------------------------------------|\n\r");
	putstr("|0x10            Line 2            0x1F|\n\r");
	putstr("|--------------------------------------|\n\r");
	putstr("|0x50            Line 3            0x5F|\n\r");
	putstr("|--------------------------------------|\n\r\n\r");

	putstr("Valid DDRAM addresses: \n\r\n\r");
	putstr("|------------------|-------------------|-------------------------------------|\n\r");
	putstr("|0x00  Line 0  0x0F|0x10   Line 2  0x1F|0x20             DDRAM           0x3F|\n\r");
	putstr("|------------------|-------------------|-------------------------------------|\n\r");
	putstr("|0x40  Line 1  0x4F|0x50   Line 3  0x5F|0x60             DDRAM           0x7F|\n\r");
	putstr("|------------------|-------------------|-------------------------------------|\n\r\n\r");
}

int getInput(char *prompt, char *retStr, int sz_retStr, int f_clear, int f_noWait) {			/* if only C allowed parameters to have default values! sigh */

	int i = 0;
	char ch = 0;
	int conv = 0;
	int sz_rc = 0;
	char tmp[2] = {0};

	if(TRUE == f_clear) {
		clearScr();
	}

	putstr(prompt);

	if(TRUE == f_noWait) {
		tmp[0] = getchar();
		conv = atoi(tmp);
		if (sz_retStr == 1) {
			*retStr = tmp[0];
		}
		else if (sz_retStr > 1) {
			retStr[0] = tmp[0];
			retStr[1] = tmp[1];
		}
	}
	else {
		sz_rc = getstr(retStr);
		if (sz_rc > sz_retStr) return EINMEM;
		conv = atoi(retStr);
	}

	return conv;
}

/*=========================================FUNCTION MAIN==========================================*/

void main() {

	char cmd = 0;
	unsigned char buf1[] = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ[]";
	//		   				/			   /			   /			   /
	char ipString[IPSMALLLEN] = {0};
	char ipChar = 0;
	char ipStringLarge[IPSTRLENGTH] = {0};
	unsigned int addr = 0;
	unsigned int gotox = 0;
	unsigned int gotoy = 0;

	serialInit(0xFF); 						//0xFF gives Baud Rate 57600
	initAll();
	clearScr();
	P1_7 = ON;								//turn on LED
	TESTPIN = 0;

	lcdinit();
	clrLcd ();
	lcdputstr("LCD DRIVER TEST ");
	lcdgotoxy(1,4);
	lcdputstr("Init OK");

	while (1) {
		printMenu();
		cmd = getchar();
		putchar(cmd);

		switch (cmd) {
			case '1': clrLcd (); break;

			case '2':
				clearScr();
				printLcdMap();
				getInput("\n\rAddress> 0x", ipString, IPSMALLLEN, FALSE, FALSE);
				addr = htoi(ipString);
				lcdgotoaddr((unsigned char)addr);
				break;

			case '3':
				clearScr();
				printLcdMap();
				gotox = getInput("Enter row (0-3) > ", ipString, IPSMALLLEN, FALSE, FALSE);
				gotoy = getInput("\n\rEnter column (0-15) > ", ipString, IPSMALLLEN, FALSE, FALSE);
				lcdgotoxy((unsigned char)gotox, (unsigned char)gotoy);
				break;

			case '4':
				getInput("Character> ", &ipChar, 1, TRUE, TRUE);
				lcdputch(ipChar);
				break;

			case '5':
				getInput("String> ", ipStringLarge, IPSTRLENGTH, TRUE, FALSE);
				lcdputstr(ipStringLarge);
				break;

			case '6':
				gotox = getInput("Line> ", &ipChar, 1, TRUE, FALSE);
				getInput("String> ", ipStringLarge, IPSTRLENGTH, FALSE, FALSE);
				lcdPrintToLine(gotox, ipStringLarge);
				break;
			case '7':
				gotox = getInput("Line> ", &ipChar, 1, TRUE, TRUE);
				clrLine(gotox);
				break;

			case '8': lcdHome(); break;

			default:
				clearScr();
				putstr("Invalid Entry, Try again! \n\r");
				myDelay(1);
		}
	}
}
